/*
 * GUI.java
 *
 * Created on Jan 24, 2010, 2:26:16 AM
 * @author Iulian Virtejanu
 */
package ro.hex.remocadm;

import java.awt.Desktop;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.jvnet.substance.api.renderers.SubstanceDefaultListCellRenderer;
import ro.hex.remocadm.telnet.commands.GetDxChannelCommand;
import ro.hex.remocadm.telnet.commands.SetDxChannelCommand;
import ro.hex.remocadm.telnet.TelnetNotifier;
import ro.hex.remocadm.telnet.commands.GetServerTypeCommand;
import ro.hex.remocadm.telnet.commands.GetVlChannelCommand;
import ro.hex.remocadm.telnet.commands.SetVlChannelCommand;

/**
 * GUI Interface of the application.
 * @author Iulian Virtejanu
 */
public class GUI extends JFrame implements TelnetNotifier {

    // current selected channel
    private int dxLastChannel = 20;
    private String vlLastChannel = "193.50";
    // list of channels read from the properties file
    private Vector<DirectXChannel> dxChannelList;
    private Vector<V4L2Channel> vlChannelList;
    // if prev/next buttons follow the channelList or just increments the
    //  current selected channel (for when searching new channels)
    private boolean buttonsNextPrevFollowList = true;
    // good ol' logger
    private Logger logger = Logger.getLogger(GUI.class);
    // context to be passed to the VLC telnet commands / threads
    private Properties vlcContext = new Properties();
    // current skin
    private String currentSkin;
    // current server type
    private String serverType;

    /** Creates new form GUI */
    public GUI() {

        // init logging
        PropertyConfigurator.configure("log4j.properties");

        // set icon
        setApplicationIcon();

        // read app properties and vlc properties
        readProperties();

        // set look and feel
        setLookAndFeel();

        logger.info("Starting RemoteCAdm...");
        initComponents();

        // detect server type
        GetServerTypeCommand stc = new GetServerTypeCommand(this, vlcContext);
        stc.start();
        try {
            stc.join();
        } catch (Throwable ie) {
            logger.error("Unable to get the server type.", ie);
        }
        serverType = stc.getServerType();

        if (!"dx".equals(serverType) && !"vl".equals(serverType)) {
            throw new IllegalArgumentException("Unrecognized server type: " + serverType);
        }

        // init UI (channels)
        DefaultListModel model = (DefaultListModel) jChannelList.getModel();
        model.clear();

        if ("dx".equals(serverType)) {
            for (int i = 0; i < dxChannelList.size(); i++) {
                model.add(i, dxChannelList.elementAt(i));
            }
        } else if ("vl".equals(serverType)) {
            for (int i = 0; i < vlChannelList.size(); i++) {
                model.add(i, vlChannelList.elementAt(i));
            }
        }

        // get current channel
        if (logger.isDebugEnabled()) {
            logger.debug("Telnet.getCurrentChannel()");
        }

        if ("dx".equals(serverType)) {
            GetDxChannelCommand gcc = new GetDxChannelCommand(this, vlcContext);
            gcc.start();
            try {
                gcc.join();
            } catch (Throwable ie) {
                logger.error("Unable to get the channel.", ie);
            }
            dxLastChannel = gcc.getLastChannel();

            if (dxLastChannel == -1) {
                dxLastChannel = dxChannelList.elementAt(0).getVlcChannel();
            }
        } else if ("vl".equals(serverType)) {
            GetVlChannelCommand gcc = new GetVlChannelCommand(this, vlcContext);
            gcc.start();
            try {
                gcc.join();
            } catch (Throwable ie) {
                logger.error("Unable to get the channel.", ie);
            }
            vlLastChannel = gcc.getLastChannel();

            if (vlLastChannel == null) {
                vlLastChannel = vlChannelList.elementAt(0).getVlcChannel();
            }
        }

        // set the UI acordingly
        updateChannelOnUi();
        logger.info("UI rendered.");
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jChannelListScrollPane = new javax.swing.JScrollPane();
        jChannelList = new javax.swing.JList();
        jChannelListLabel = new javax.swing.JLabel();
        jStatusBar = new javax.swing.JProgressBar();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jChannelNavigationPanel = new javax.swing.JPanel();
        jPrevButton = new javax.swing.JButton();
        channelTextField = new javax.swing.JTextField();
        jNextButton = new javax.swing.JButton();
        jAboutPanel = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        jVisitHomePage = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("RemoCAdm");

        jChannelList.setModel(new DefaultListModel());
        jChannelList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jChannelList.setCellRenderer(new SubstanceDefaultListCellRenderer());
        jChannelList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jChannelListMouseClicked(evt);
            }
        });
        jChannelList.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                jChannelListKeyPressed(evt);
            }
        });
        jChannelListScrollPane.setViewportView(jChannelList);

        jChannelListLabel.setText("Channels:");

        jStatusBar.setString(" ");
        jStatusBar.setStringPainted(true);

        jPrevButton.setText("Prev.");
        jPrevButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jPrevButtonActionPerformed(evt);
            }
        });

        channelTextField.setText("20");
        channelTextField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                channelTextFieldActionPerformed(evt);
            }
        });

        jNextButton.setText("Next");
        jNextButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jNextButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jChannelNavigationPanelLayout = new javax.swing.GroupLayout(jChannelNavigationPanel);
        jChannelNavigationPanel.setLayout(jChannelNavigationPanelLayout);
        jChannelNavigationPanelLayout.setHorizontalGroup(
            jChannelNavigationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jChannelNavigationPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jChannelNavigationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(channelTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE)
                    .addComponent(jPrevButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jNextButton, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE))
                .addGap(105, 105, 105))
        );
        jChannelNavigationPanelLayout.setVerticalGroup(
            jChannelNavigationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jChannelNavigationPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPrevButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(channelTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jNextButton)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jTabbedPane1.addTab("Channel", jChannelNavigationPanel);

        jLabel2.setText("© Iulian Virtejanu, 2010");

        jVisitHomePage.setText("Visit Project Page");
        jVisitHomePage.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jVisitHomePageActionPerformed(evt);
            }
        });

        jLabel3.setText("Remote Ch Adm. 1.0a");

        javax.swing.GroupLayout jAboutPanelLayout = new javax.swing.GroupLayout(jAboutPanel);
        jAboutPanel.setLayout(jAboutPanelLayout);
        jAboutPanelLayout.setHorizontalGroup(
            jAboutPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jAboutPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jAboutPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jAboutPanelLayout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addContainerGap(48, Short.MAX_VALUE))
                    .addGroup(jAboutPanelLayout.createSequentialGroup()
                        .addComponent(jLabel3)
                        .addContainerGap(58, Short.MAX_VALUE))
                    .addGroup(jAboutPanelLayout.createSequentialGroup()
                        .addComponent(jVisitHomePage, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGap(77, 77, 77))))
        );
        jAboutPanelLayout.setVerticalGroup(
            jAboutPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jAboutPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel3)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jVisitHomePage)
                .addGap(28, 28, 28))
        );

        jTabbedPane1.addTab("About", jAboutPanel);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jStatusBar, javax.swing.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jChannelListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 179, Short.MAX_VALUE)
                    .addComponent(jChannelListLabel)
                    .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 179, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jChannelListLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jChannelListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 235, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(jStatusBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        jTabbedPane1.getAccessibleContext().setAccessibleName("Channel");

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jPrevButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jPrevButtonActionPerformed
        if ("dx".equals(serverType)) {
            if (buttonsNextPrevFollowList) {
                int sel = jChannelList.getSelectedIndex();
                if (sel > 0) {
                    dxLastChannel = dxChannelList.elementAt(sel - 1).getVlcChannel();
                    setChannel();
                }
            } else if (dxLastChannel > 0) {
                dxLastChannel--;
                setChannel();
            }
        } else if ("vl".equals(serverType)) {
            int sel = jChannelList.getSelectedIndex();
            if (sel > 0) {
                vlLastChannel = vlChannelList.elementAt(sel - 1).getVlcChannel();
                setChannel();
            }
        }
    }//GEN-LAST:event_jPrevButtonActionPerformed

    private void channelTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_channelTextFieldActionPerformed
        if ("dx".equals(serverType)) {
            dxLastChannel = Integer.parseInt(channelTextField.getText());
        } else if ("vl".equals(serverType)) {
            vlLastChannel = channelTextField.getText();
        }
        setChannel();
    }//GEN-LAST:event_channelTextFieldActionPerformed

    private void jNextButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jNextButtonActionPerformed
        if ("dx".equals(serverType)) {
            if (buttonsNextPrevFollowList) {
                int sel = jChannelList.getSelectedIndex();
                if (sel < dxChannelList.size() - 1) {
                    dxLastChannel = dxChannelList.elementAt(sel + 1).getVlcChannel();
                    setChannel();
                }
            } else {
                dxLastChannel++;
                setChannel();
            }
        } else if ("vl".equals(serverType)) {
            int sel = jChannelList.getSelectedIndex();
            if (sel < vlChannelList.size() - 1) {
                vlLastChannel = vlChannelList.elementAt(sel + 1).getVlcChannel();
                setChannel();
            }
        }
    }//GEN-LAST:event_jNextButtonActionPerformed

    private void jChannelListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jChannelListMouseClicked
        if (evt.getClickCount() % 2 == 0) {
            if ("dx".equals(serverType)) {
                DirectXChannel c = (DirectXChannel) jChannelList.getSelectedValue();
                dxLastChannel = c.getVlcChannel();
                setChannel();
            } else if ("vl".equals(serverType)) {
                V4L2Channel c = (V4L2Channel) jChannelList.getSelectedValue();
                vlLastChannel = c.getVlcChannel();
                setChannel();
            }
        }
    }//GEN-LAST:event_jChannelListMouseClicked

    private void jChannelListKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jChannelListKeyPressed
        if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
            if ("dx".equals(serverType)) {
                dxLastChannel = dxChannelList.elementAt(jChannelList.getSelectedIndex()).getVlcChannel();
                setChannel();
            } else if ("vl".equals(serverType)) {
                vlLastChannel = vlChannelList.elementAt(jChannelList.getSelectedIndex()).getVlcChannel();
                setChannel();
            }
        }
    }//GEN-LAST:event_jChannelListKeyPressed

    private void jVisitHomePageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jVisitHomePageActionPerformed
        try {
            Desktop.getDesktop().browse(new URI("http://code.google.com/p/remotecadm/"));
        } catch (Throwable ex) {
            logger.error("Unable to connect to application home page.", ex);
        }
    }//GEN-LAST:event_jVisitHomePageActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        JFrame.setDefaultLookAndFeelDecorated(true);
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                GUI gui = new GUI();
                // enable global double buffer
                RepaintManager currentManager = RepaintManager.currentManager(gui);
                currentManager.setDoubleBufferingEnabled(true);

                centreFrameOnScreen(gui);

                gui.setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField channelTextField;
    private javax.swing.JPanel jAboutPanel;
    private javax.swing.JList jChannelList;
    private javax.swing.JLabel jChannelListLabel;
    private javax.swing.JScrollPane jChannelListScrollPane;
    private javax.swing.JPanel jChannelNavigationPanel;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JButton jNextButton;
    private javax.swing.JButton jPrevButton;
    private javax.swing.JProgressBar jStatusBar;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JButton jVisitHomePage;
    // End of variables declaration//GEN-END:variables

    private void setChannel() {
        updateChannelOnUi();
        if ("dx".equals(serverType)) {
            vlcContext.setProperty("vlc.channel", "" + dxLastChannel);
            SetDxChannelCommand scc = new SetDxChannelCommand(this, vlcContext);
            scc.start();
        } else if ("vl".equals(serverType)) {
            vlcContext.setProperty("vlc.channel", mhztokhz(vlLastChannel));
            SetVlChannelCommand scc = new SetVlChannelCommand(this, vlcContext);
            scc.start();
        }
    }

    /**
     * Converts "192.25" to "192250"
     * @param mhzValue
     */
    private String mhztokhz(String mhzValue) {
        String result = "";

        // suppress point
        StringBuilder sb = new StringBuilder(mhzValue);
        int pointPos = sb.indexOf(".");
        if (pointPos != -1)
            sb.deleteCharAt(pointPos);

        for (int i = 0; i < 6 - sb.length(); i++) {
            sb.append("0");
        }

        return sb.toString();
    }

    /**
     * Reads properties file and populates internal variables.
     */
    private void readProperties() {
        logger.info("entered.");
        dxChannelList = new Vector<DirectXChannel>();
        vlChannelList = new Vector<V4L2Channel>();

        File confFile = new File("remotecadm.conf");
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(confFile), "UTF-8"));
            String line = br.readLine();
            while (line != null) {
                if (!line.startsWith("#")) {
                    if (line.startsWith("dx.")) {
                        dxChannelList.addElement(DirectXChannel.parseChannel(line));
                    }
                    if (line.startsWith("vl.")) {
                        vlChannelList.addElement(V4L2Channel.parseChannel(line));
                    }
                    if (line.startsWith("nav.buttons.follow.list")) {
                        buttonsNextPrevFollowList = readBoolean(line);
                    }
                    if (line.startsWith("vlc.")) {
                        int ie = line.indexOf('=');
                        vlcContext.setProperty(line.substring(0, ie), line.substring(ie + 1));
                    }
                    if (line.startsWith("gui.skin")) {
                        int ie = line.indexOf('=');
                        currentSkin = line.substring(ie + 1);
                    }
                }
                line = br.readLine();
            }
        } catch (Throwable t) {
            logger.error("Unable to read properties file.", t);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException ex) {
                    logger.error("Unable to close the stream of the config file:", ex);
                }
            }
        }
    }

    /**
     * Updates the list to point to the last selected channel
     */
    private void updateChannelOnUi() {
        DefaultListModel model = (DefaultListModel) jChannelList.getModel();
        if ("dx".equals(serverType)) {
            // search channel in the list      
            boolean found = false;
            for (int i = 0; i < model.getSize(); i++) {
                DirectXChannel c = (DirectXChannel) model.elementAt(i);

                if (c.getVlcChannel() == dxLastChannel) {
                    jChannelList.setSelectedValue(c, true);
                    found = true;
                }
            }
            if (!found) {
                jChannelList.setSelectedIndex(-1);
            }

            channelTextField.setText(dxLastChannel + "");
        }  else if ("vl".equals(serverType)) {
            // search channel in the list
            boolean found = false;
            for (int i = 0; i < model.getSize(); i++) {
                V4L2Channel c = (V4L2Channel) model.elementAt(i);

                if (c.getVlcChannel().equals(vlLastChannel)) {
                    jChannelList.setSelectedValue(c, true);
                    found = true;
                }
            }
            if (!found) {
                jChannelList.setSelectedIndex(-1);
            }

            channelTextField.setText(vlLastChannel + "");
        }
    }

    private boolean readBoolean(String string) {
        int indexOfEquals = string.indexOf('=');
        return Boolean.parseBoolean(string.substring(indexOfEquals + 1));
    }

    public void setBusy(boolean busy) {
        String message = busy ? "Please wait ..." : " ";
        jStatusBar.setString(message);
        jStatusBar.setIndeterminate(busy);
    }

    /**
     * Updates status of GUI.
     * @param event
     * @param payload
     */
    public void updateStatus(int event, Object payload) {
        switch (event) {
            case TelnetNotifier.START_EVENT:
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        setBusy(true);
                    }
                });
                break;
            case TelnetNotifier.ERROR_EVENT:
                Throwable t = (Throwable) payload;
                logger.error("Connection failure: ", t);
            // fallback to END_EVENT just to disable the progress bar.
            case TelnetNotifier.END_EVENT:
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        setBusy(false);
                    }
                });
                break;
        }
    }

    private void setApplicationIcon() {
        try {
            int iconSizes[] = new int[]{16, 22, 32, 48, 64, 128};
            ArrayList<Image> icons = new ArrayList<Image>();
            for (int i = 0; i < iconSizes.length; i++) {
                InputStream is = this.getClass().getResourceAsStream("/ro/hex/remocadm/resources/" + iconSizes[i] + ".png");
                icons.add(ImageIO.read(is));
            }
            setIconImages(icons);
        } catch (Exception e) {
            logger.error("Unable to set application images.", e);
        }
    }

    /**
     * Sets the look and feel based on the 'gui.skin' parameter in configuration
     * file.
     */
    private void setLookAndFeel() {
        if (currentSkin == null) {
            logger.warn("gui.skin parameter not found in conf file.");
            return;
        } else {
            String laf = "org.jvnet.substance.skin." + currentSkin;
            try {
                UIManager.setLookAndFeel(laf);
                SwingUtilities.updateComponentTreeUI(this);
            } catch (Throwable e) {
                logger.error("Skin " + laf + " exception.", e);
            }
        }
    }

    /**
     * Centers current JFrame on the screen.
     * @param frame
     */
    public static void centreFrameOnScreen(JFrame frame) {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        Point center = ge.getCenterPoint();
        int w = frame.getWidth();
        int h = frame.getHeight();
        int x = center.x - w / 2, y = center.y - h / 2;
        frame.setBounds(x, y, w, h);
        frame.validate();
    }
}
